package org.apache.lucene.distributed.index;

/**
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.io.FileUtils;
import org.apache.lucene.distributed.RMI;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;

/**
 * 
 *
 */
public class LuceneServer {
  RMI rmi;
  File dir;
  Map<String,IndexServiceImpl> indexes = new HashMap<String,IndexServiceImpl>();
  IndexManagerServiceImpl indexManagerServiceImpl;
  RMI.Server rmiServer;
  
  /**
   * 
   * @param rmi
   * @param dir Directory where index directories will be created
   * @throws Exception
   */
  public LuceneServer(RMI rmi, File dir) throws Exception {
    this.rmi = rmi;
    rmiServer = rmi.getServer();
    this.dir = dir;
    indexManagerServiceImpl = new IndexManagerServiceImpl();
    rmi.getServer().addService("indexManagerService", indexManagerServiceImpl, false);
    for (File file : dir.listFiles()) {
      String name = file.getName();
      if (file.isDirectory() && name.startsWith("index.")) {
        String indexName = name.substring(name.indexOf('.'), name.length());
        indexManagerServiceImpl.createIndex(indexName, file, null);
      }
    }
  }

  public class IndexManagerServiceImpl implements IndexManagerService {
    /**
     * Creates an index if it is not already there, otherwise returns the existing index.
     */
    public IndexService createIndex(String name, IndexSettings indexSettings) throws Exception {
      File indexDir = new File(dir, name);
      if (!indexDir.exists())
        indexDir.mkdirs();
      return createIndex(name, indexDir, indexSettings);
    }
    
    public IndexService getIndex(String name) throws Exception {
      return createIndex(name, null);
    }
    
    private IndexService createIndex(String name, File dir, IndexSettings indexSettings) throws Exception {
      File indexSettingsFile = new File(dir, "indexsettings.obj");
      if (indexSettings != null) {
        if (!indexSettingsFile.exists()) {
          // save the classes that are special to the serialized object
          // TODO: use saveclassobjectoutputstream
          FileOutputStream fileOut = new FileOutputStream(indexSettingsFile);
          ObjectOutputStream objOut = rmiServer.getRMIClasses().createOutput(fileOut, rmiServer, true);
          objOut.writeObject(indexSettings);
          objOut.close();
        }
      } else {
        if (indexSettingsFile.exists()) {
          // load special classes from the serialized object
          ObjectInputStream objIn = rmiServer.getRMIClasses().createInput(new FileInputStream(indexSettingsFile), rmi, true);
          indexSettings = (IndexSettings) objIn.readObject();
        }
      }
      Directory directory = FSDirectory.getDirectory(dir);
      String serviceName = "index." + name;
      IndexServiceImpl indexServiceImpl = new IndexServiceImpl(name, serviceName, directory, indexSettings, rmi.getServer());
      indexes.put(name, indexServiceImpl);
      rmiServer.addService(serviceName, indexServiceImpl, false);
      return indexServiceImpl;
    }

    public IndexInfo[] getIndexInfos() throws Exception {
      List<IndexInfo> infos = new ArrayList<IndexInfo>();
      for (File file : dir.listFiles()) {
        if (file.isDirectory()) {
          String name = file.getName();
          if (name.startsWith("index.")) {
            infos.add(getIndexInfo(file));
          }
        }
      }
      return (IndexInfo[])infos.toArray(new IndexInfo[0]);
    }
    
    private IndexInfo getIndexInfo(File d) throws Exception {
      String n = d.getName();
      String name = n.substring(n.indexOf('.')+1, n.length());
      IndexInfo indexInfo = new IndexInfo();
      File indexSettingsFile = new File(dir, "indexsettings.obj");
      ObjectInputStream objIn = rmiServer.getRMIClasses().createInput(new FileInputStream(indexSettingsFile), rmi, true);
      indexInfo.indexSettings = (IndexSettings) objIn.readObject();
      indexInfo.length = FileUtils.sizeOfDirectory(d);
      indexInfo.name = name;
      return indexInfo;
    }
    
    public void deleteIndex(String name) throws Exception {
      IndexServiceImpl isi = indexes.get(name);
      if (isi != null)
        isi.close();
      if (isi.directory instanceof FSDirectory)
        FileUtils.deleteDirectory(((FSDirectory)isi.directory).getFile());
    }
  }
}
